package saati.core.consistency;

import saati.core.concordance.AbstractConcordanceCalculator;
import saati.core.concordance.ConcordanceCalculator;
import saati.core.concordance.RelationConcordanceCalculator;

import java.util.ArrayList;
import java.util.List;

import static saati.utils.ArrayUtil.findOccurrence;
import static saati.utils.ArrayUtil.getColumn;

public class ConsistencyChecker {

    private int[][] rangeMatrix;
    private int expertsCount;
    private int alternativesCount;
    private Double concordance;
    private List<Integer> summaryRangList;
    private Double mathExpectation;

    public ConsistencyChecker(int[][] rangeMatrix) {
        this.rangeMatrix = rangeMatrix;
        this.alternativesCount = rangeMatrix.length;
        this.expertsCount = rangeMatrix[0].length;
    }

    public boolean verifyConsistency() {
        summaryRangList = calculateSummaryRanges();
        mathExpectation = calculateMathExpectation(summaryRangList);
        AbstractConcordanceCalculator calculator = getConcordanceStrategy();
        calculator.setRangeMatrix(rangeMatrix);
        concordance = calculator.getConcordance(mathExpectation, summaryRangList);
        return ((concordance >= 0.5) && (concordance <= 1));
    }


    private List<Integer> calculateSummaryRanges() {
        List<Integer> summaryRangList = new ArrayList<Integer>();
        for (int i = 0; i < alternativesCount; i++) {
            int sum = 0;
            for (int j = 0; j < expertsCount; j++) {
                sum += rangeMatrix[i][j];
            }
            summaryRangList.add(sum);
        }
        return summaryRangList;
    }

    private boolean hasRelatedRange() {
        for (int i = 0; i < expertsCount; i++) {
            for (int j = 0; j < alternativesCount; j++) {
                if (findOccurrence(getColumn(rangeMatrix, i), rangeMatrix[j][i]) > 1) {
                    return true;
                }
            }
        }
        return false;
    }

    private AbstractConcordanceCalculator getConcordanceStrategy() {
        return hasRelatedRange() ? new RelationConcordanceCalculator() : new ConcordanceCalculator();
    }

    private Double calculateMathExpectation(List<Integer> summaryRangList) {
        Double sum = 0d;
        for (Integer r : summaryRangList) {
            sum += r;
        }
        return sum / alternativesCount;
    }

    public int[][] getRangeMatrix() {
        return rangeMatrix;
    }

    public int getExpertsCount() {
        return expertsCount;
    }

    public int getAlternativesCount() {
        return alternativesCount;
    }

    public Double getConcordance() {
        return concordance;
    }

    public List<Integer> getSummaryRangList() {
        return summaryRangList;
    }

    public Double getMathExpectation() {
        return mathExpectation;
    }
}
